﻿Function IP-toINT64 () 
    {
    Param ($IP)
    $Octets = $IP.split(".")
    Return [int64]([int64]$octets[0]*16777216 +[int64]$octets[1]*65536 +[int64]$octets[2]*256 +[int64]$octets[3])
    }
Function INT64-toIP()
    {
    Param ([int64]$int)
    Return (([math]::truncate($int/16777216)).tostring()+"."+([math]::truncate(($int%16777216)/65536)).tostring()+"."+([math]::truncate(($int%65536)/256)).tostring()+"."+([math]::truncate($int%256)).tostring() )
    }
# Get-IPRange function
Function Get-IPrange
    {
    <#
      .SYNOPSIS
        Get the IP addresses in a range
      .EXAMPLE
       Get-IPrange -start 192.168.8.2 -end 192.168.8.20
      .EXAMPLE
       Get-IPrange -ip 192.168.8.2 -mask 255.255.255.0
      .EXAMPLE
       Get-IPrange -ip 192.168.8.3 -cidr 24
    #>
    Param
        (
        [string]$Start,
        [string]$End,
        [string]$IP,
        [string]$Mask,
        [int]$CIDR
        )  

    #Initialization
    #Get DNS server from the active NIC DNS List
    [Array]$DNSServer = Get-NetAdapter | Where AdminStatus -EQ "up" | Get-DnsClientServerAddress -AddressFamily IPv4
    [Array]$DNSSuffixes = Get-DnsClientGlobalSetting | Select-Object SuffixSearchList
    [Array]$DHCPinDC = @()
    [Array]$DHCPIPs = @()
    [Array]$DHCPAllIPs = @()
    [Array]$IPToCSV = @() | Select IPAddress, DeviceName, AssignmentDate, ExpiryDate, IpAddressState, Description
    [Array]$IPToMem = @() | Select IPAddress, DeviceName, AssignmentDate, ExpiryDate, IpAddressState, Description
    [String]$DNSSuffix = $DNSSuffixes.SuffixSearchList
    $Ping = New-Object System.Net.Networkinformation.ping
    $DHCPinDC = Get-DhcpServerInDC
    $DHCPAllIPs = @() | Select IPAddress, MACAddress, DeviceName, ExpiryDate, Description, AssignmentType
    ForEach ($DHCPServer in $DHCPinDC) #"$env:LOGONSERVER.$Env:USERDNSDOMAIN"
        {
        $DHCPIPs = Get-DhcpServerv4Scope -ComputerName $DHCPServer.DNSName |
            ForEach-Object
                {
                Get-DhcpServerv4Lease -ComputerName $DHCP -ScopeId $_.ScopeId |
                    Select-Object @{Name="IPAddress";Expression={$_.ipaddress}},
                                  @{Name="MACAddress";Expression={$_.clientid}},
                                  @{Name="DeviceName";Expression={$_.hostname}},
                                  @{Name="ExpiryDate";Expression={$_.leaseexpirytime}},
                                  @{Name="Description";Expression={$_.description}},
                                  @{Name="AssignmentType";Expression="Dynamic"}
                }
        $DHCPAllIPs += $DHCPIPs
        }
    # 
    If ($IP) {$IPAddr = [Net.IPAddress]::Parse($IP)}  
    If ($CIDR) {$MaskAddr = [Net.IPAddress]::Parse((INT64-toIP -int ([convert]::ToInt64(("1"*$CIDR+"0"*(32-$CIDR)),2)))) }  
    If ($Mask) {$MaskAddr = [Net.IPAddress]::Parse($Mask)}
    If ($IP) {$NetworkAddr = new-object net.ipaddress ($MaskAddr.address -band $IPAddr.address)}  
    If ($IP) {$BroadcastAddr = new-object net.ipaddress (([system.net.ipaddress]::parse("255.255.255.255").address -bxor $MaskAddr.address -bor $NetworkAddr.address))}  
  
    If ($IP) {  
      $StartAddr = IP-toINT64 -ip $NetworkAddr.ipaddresstostring  
      $EndAddr = IP-toINT64 -ip $BroadcastAddr.ipaddresstostring  
    } else {  
      $StartAddr = IP-toINT64 -ip $Start  
      $EndAddr = IP-toINT64 -ip $End  
    }  
  
    #Add 1 to $StartAddr to get the first subnet's IP
    #The last IP is -lt (LessThan) to do not test the broadcast address
    $StartAddr ++
    For ($i = $StartAddr; $i -lt $EndAddr; $i++)
        {
        $IPToTest = INT64-toIP -int $i
        # Test if the address is managed by DHCP
        IF (!($DHCPAllIPs."IPAddress" -contains $IPToTest))
            {
            #$IPUsed = Test-Connection -ComputerName $IPToTest -Count 1 -Quiet ### Removed: too slow - the timeout is 3000ms
            $IPUsed = $Ping.Send($IPToTest,100)
            $IFNotUsed = "is not used"
            $IfContainsName = ""
            If ($IPUsed.Status -like "Success")
                {
                $IfNotUsed = "IN-Use."
                $IPToName = Resolve-DNSName -Name $IPToTest -DnsOnly -ErrorAction SilentlyContinue
                If ($IPToName)
                    {$IfContainsName = "The hostname is: " + $IPToName.NameHost}
                Else
                    {
                    $IfContainsName = "No PTR record found."
                    $DNSA = Get-DnsServerResourceRecord -ZoneName $DnsSuffix -ComputerName $DNSServer.ServerAddresses[0] | Where {$_.RecordData.IPV4Address -match $IPToTest}
                    If ($DNSA.HostName  -ne $Null)
                        {$IfContainsName = $IfContainsName + " Record A found: " + $DNSA.HostName + "." + $DNSSuffix}
                    }
                }
            Write-Host "IP:" $IPToTest $IFNotUSed $IfContainsName
            #Output format: IPAddress, MACAddress, DeviceName, ExpiryDate, Description, AssignmentType

            $IPToCSV += $IPToMem
            }
        }
    $IPToCSV | Export-Csv ResultsOK-existing.csv -NoTypeInformation -Encoding UTF8

    }
#############################################################
# Main processing
#############################################################
# Initialization
$SubnetDiscovery = Get-ADReplicationSubnet -Filter {cn -Like "*"} | Select Name
# Process all subnets in Active Directory
ForEach ($Subnet in $SubnetDiscovery)
    {
    $Network = $Subnet.Name.Split("//")
    Get-IPrange -ip $Network[0] -cidr $Network[1]
    }